import React, { memo, useMemo, useState, useCallback, useRef, forwardRef, useImperativeHandle } from 'react';
import Table from './../table/Table';
import PageHeader from './../pageHeader/PageHeader';
import Search from './../search/Search';
import Button from './../button/Button';
import Edit from './Edit';
import { CRUDProps, CRUDRefProps } from './interface';
import { snedAction } from './crudApi';
import { TableRefProps } from './../table/interface';
import { message } from 'antd';
import ApiQuery from './../../interface/apiQuery'
import ActionText from './../actionText/ActionText'
import { PlusOutlined } from '@ant-design/icons'
import history from './../../app/history'

const actionColumn = { dataIndex: 'action', fixed: 'right', width: 100 };
const t = window.$app.t;
const labelCol = { span: 7 };
const wrapperCol = { span: 10 };
const layout = 'horizontal';
const groupNumber = 1;

function CRUD({ placeholder, searchFields, baseUrl, columns, urls, formItems, saveDataAfter, saveDataBefore, getDataAfter, showCreateModalBefore,
  onValuesChange, deleteDataAfter, tableExtra, formExtra }: CRUDProps, ref: React.Ref<CRUDRefProps>) {

  const tableRef = useRef<TableRefProps>(null);
  const [visible, setVisible] = useState(false);
  const [curLine, setCurLine] = useState<any>({});
  const [query, setQuery] = useState<ApiQuery>({});
  
  useImperativeHandle(ref, () => ({
    onRefresh: () => tableRef.current?.onRefresh()
  }));

  const showEdit = useCallback(async (line?: any) => {
    let handleLine = line;
    if (line && getDataAfter) handleLine = await getDataAfter(line);

    const dataSource = tableRef.current?.getDataSource();
    showCreateModalBefore?.(line, dataSource);

    setVisible(true);
    setCurLine(handleLine || {});
  }, [getDataAfter, showCreateModalBefore]);

  const hideEdit = useCallback(() => {
    setVisible(false);
    setCurLine({});
  }, []);

  const { findUrl, removeUrl, updateUrl, addUrl } = useMemo(() => {
    const findUrl = urls?.findUrl || (baseUrl + '/find');
    const removeUrl = urls?.removeUrl || (baseUrl + '/delete');
    const updateUrl = urls?.updateUrl || (baseUrl + '/update');
    const addUrl = urls?.addUrl || (baseUrl + '/add');
    return { findUrl, removeUrl, updateUrl, addUrl }
  }, [baseUrl, urls]);

  const onOk = useCallback(async (values: any) => {
    setVisible(false);
    const action = values.id ? updateUrl : addUrl;
    let data = { ...values };
    if (saveDataBefore) data = await saveDataBefore(values);

    if (!data) return; // 处理服务器错误
    if (typeof data === 'string') return message.warning(data);

    const result = await snedAction(action, { data });
    if (saveDataAfter) saveDataAfter(data, result);

    tableRef.current?.onRefresh();
    setCurLine({});
  }, [updateUrl, addUrl, saveDataBefore, saveDataAfter]);

  const remove = useCallback(async (data: any) => {
    setVisible(false);

    await snedAction(removeUrl, { data: { id: data.id } });

    if (deleteDataAfter) await deleteDataAfter(data);
    tableRef.current?.onRefresh();
    setCurLine({});
  }, [removeUrl, deleteDataAfter]);

  const onDoubleClick = useCallback((record) => showEdit(record), [showEdit]);

  const TableExtra = useMemo(() => {
    const isActionColumn = tableExtra?.some(item => item.dataIndex === 'action');

    if (!isActionColumn) {
      return (tableExtra || []).concat({
        dataIndex: 'action',
        render(text: string, record: any) {
          return (
            <>
              <ActionText.Edit onClick={() => showEdit(record)} />
              <ActionText.Delete isModalTip onClick={() => remove(record)} />
            </>
          )
        }
      })
    }

    return tableExtra?.map(item => {
      return {
        ...item, render(text: string, record: any, index: number) {
          return item.render(text, record, index, { remove, showEdit })
        }
      }
    })
  }, [showEdit, remove, tableExtra]);

  const handleColumns = useMemo(() => {
    if (columns.some(item => item.dataIndex === 'action')) return columns;
    return columns.concat(actionColumn)
  }, [columns]);

  const onSearch = useCallback((fuzzyValue: string) => {
    setQuery({ fuzzyField: searchFields, fuzzyQuery: true, fuzzyValue })
  }, [searchFields]);

  return (
    <>
      <div className='common-block-table'>
        <PageHeader title={t(history.location.pathname)} extra={
          <>
            {!!(searchFields && searchFields.length) && <Search placeholder={placeholder} onSearch={onSearch} />}
            <Button.Create onClick={() => showEdit({})} key='create'><PlusOutlined />{window.$app.t('add')}</Button.Create>
          </>
        } />
        <Table onDoubleClick={onDoubleClick} ref={tableRef} columns={handleColumns} query={query} url={findUrl} extra={TableExtra} />
      </div>
      <Edit onOk={onOk} onRemove={remove} initialValues={curLine} onValuesChange={onValuesChange} layout={layout} groupNumber={groupNumber}
        labelCol={labelCol} wrapperCol={wrapperCol} onCancel={hideEdit} visible={visible} formItems={formItems} formExtra={formExtra} />
    </>
  )
}

export default memo(forwardRef(CRUD));